package com.example.hotel.blImpl.order;

import com.example.hotel.bl.hotel.HotelService;
import com.example.hotel.bl.hotel.RoomRepoService;
import com.example.hotel.bl.hotel.RoomService;
import com.example.hotel.bl.order.OrderService;

import com.example.hotel.bl.user.AccountService;

import com.example.hotel.data.credit.CreditMapper;
import com.example.hotel.data.order.OrderMapper;
import com.example.hotel.enums.CreditAction;
import com.example.hotel.enums.RoomType;

import com.example.hotel.po.CreditInfo;
import com.example.hotel.po.HotelRoom;
import com.example.hotel.po.Order;
import com.example.hotel.po.User;
import com.example.hotel.vo.DatePeriodVO;
import com.example.hotel.vo.HotelVO;
import com.example.hotel.vo.OrderVO;
import com.example.hotel.vo.ResponseVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: zl
 * @Date: 2021-06-26
 */
@Service
public class OrderServiceImpl implements OrderService {
    private final static String RESERVE_ERROR = "预订失败";
    private final static String ROOMNUM_LACK = "预订房间数量剩余不足";
    @Autowired
    OrderMapper orderMapper;
    @Autowired
    CreditMapper creditMapper;

    @Autowired
    HotelService hotelService;
    @Autowired
    AccountService accountService;
    @Autowired
    RoomService roomService;
    @Autowired
    RoomRepoService roomRepoService;
    @Override

    /**
    预订酒店,增加一条订单信息
     */
    public ResponseVO addOrder(OrderVO orderVO) {

        try {
            SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
            Date date = new Date(System.currentTimeMillis());
            String curdate = sf.format(date);
            orderVO.setCreateDate(curdate);
            orderVO.setOrderState("已预订");
            User user = accountService.getUserInfo(orderVO.getUserId());
            orderVO.setClientName(user.getUserName());
            orderVO.setPhoneNumber(user.getPhoneNumber());
            Order order = new Order();
            BeanUtils.copyProperties(orderVO,order);
//            orderMapper.addOrder(order);
//            hotelService.updateRoomInfo(orderVO.getHotelId(),orderVO.getRoomType(),orderVO.getRoomNum());
            //修改roomrepo表
            //获取roomId
            HotelRoom hotelRoom = roomService.selectRoomByHotelIdAndType(orderVO.getHotelId(),orderVO.getRoomType());
            int roomId = hotelRoom.getId();
//            roomRepoService里面写set(roomid ,start,end,newValue)和get(roomid ,start,end) TODO
            String checkInDate = order.getCheckInDate();
            String checkOutDate = order.getCheckOutDate();
            DatePeriodVO datePeriodVO = new DatePeriodVO();
            datePeriodVO.setFromDate(checkInDate);
            datePeriodVO.setRoomId(roomId);
            datePeriodVO.setToDate(checkOutDate);
            datePeriodVO.setValToSet(null);
            Map<String,Integer> rooms = roomRepoService.getForPeriod(datePeriodVO);
            Integer min = (Integer)this.getMinValue(rooms);
            //如果没房了，显示房间不足
            if(min<order.getRoomNum()){
                return ResponseVO.buildFailure(ROOMNUM_LACK);
            }
            orderMapper.addOrder(order);
            roomRepoService.updateAvailableOfRoomIdAndDates(roomId,checkInDate,checkOutDate,-order.getRoomNum());


        } catch (Exception e) {
            System.out.println(e.getMessage());
            return ResponseVO.buildFailure(RESERVE_ERROR);
        }
       return ResponseVO.buildSuccess(true);
    }

    //获得所有酒店的所有订单信息
    @Override
    public List<Order> getAllOrders() {
        return orderMapper.getAllOrders();
    }

    //获得指定用户的所有订单信息
    @Override
    public List<Order> getUserOrders(int userid) {
        return orderMapper.getUserOrders(userid);
    }


    //撤销一条订单
    @Override
    public ResponseVO annulOrder(int orderid) {
        //取消订单逻辑的具体实现（注意可能有和别的业务类之间的交互）
        //先修改订单状态，改为已取消
        int rowNum = orderMapper.annulOrder(orderid);
        //得到订单，用来修改房间信息
        Order order = orderMapper.getOrderById(orderid);
        //修改roomrepo表
        //获取roomId
        HotelRoom hotelRoom = roomService.selectRoomByHotelIdAndType(order.getHotelId(),order.getRoomType());
        int roomId = hotelRoom.getId();
//            roomRepoService里面写set(roomid ,start,end,newValue)和get(roomid ,start,end)
        String checkInDate = order.getCheckInDate();
        String checkOutDate = order.getCheckOutDate();

        roomRepoService.updateAvailableOfRoomIdAndDates(roomId,checkInDate,checkOutDate,order.getRoomNum());

        if (rowNum>0){return ResponseVO.buildSuccess(true);}
        else return ResponseVO.buildSuccess(false);

    }


    //查看酒店的所有订单
    @Override
    public List<Order> getHotelOrders(Integer hotelId) {
        System.out.println("nuu");
        List<Order> orders = getAllOrders();
        return orders.stream().filter(order -> order.getHotelId().equals(hotelId)).collect(Collectors.toList());
    }



    //浏览订单详情
    //没用VO 因为上面的都是Order不是VO
    @Override
    public Order getOrderDetail(Integer orderid) {
        return orderMapper.getOrderById(orderid);
    }



    //订单执行chekin
    @Override
    public ResponseVO checkInOrder(int orderid) {
        //先checkin,然后得到订单,通过订单得到用户,给用户更新credit
        Order order = orderMapper.getOrderById(orderid);
        if(order.getOrderState().equals("已预订")||order.getOrderState().equals("异常")) {
            int rowNum = orderMapper.checkInOrder(orderid);
            if (rowNum > 0) {

                int userid = order.getUserId();

                User user = accountService.getUserInfo(userid);
                double beforeCredit = user.getCredit();
                double newCredit = beforeCredit + order.getPrice();
                //更新
                int rowNum2 = accountService.updateAccountCredit(userid, newCredit);

                //更新入住日期
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                LocalDateTime nowTime = LocalDateTime.now();
                String nowDate = nowTime.toLocalDate().toString();
                orderMapper.updateOrderCheckInDate(orderid, nowDate);
                //增加credit记录
                CreditInfo creditInfo = new CreditInfo();
                creditInfo.setAction(CreditAction.OrderExec);
                creditInfo.setTime(order.getCheckInDate());
                creditInfo.setOrderId(orderid);
                creditInfo.setChangeVal(order.getPrice());
                creditInfo.setAfterChange(newCredit);
                creditInfo.setUserId(userid);
                creditMapper.addCreditInfo(creditInfo);
                return ResponseVO.buildSuccess(true);
            } else return ResponseVO.buildFailure("执行失败");
        }else return ResponseVO.buildFailure("执行失败");

    }


    /**
     * 查看一个订单是否异常,异常就减信用积分
     * @param orderid
     */
    public void checkAndUpdateStateOneOrder(int orderid){
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        Order order = orderMapper.getOrderById(orderid);
        String scheduledCheckInDate = order.getCheckInDate();
        //当天
        LocalDateTime scheduledCheckInDate2 = LocalDateTime.parse(scheduledCheckInDate+" 00:00:00", formatter);
        //下面一天
        scheduledCheckInDate2= scheduledCheckInDate2.plusDays(1);

        LocalDateTime nowTime = LocalDateTime.now();

        if(nowTime.isAfter(scheduledCheckInDate2) &&order.getOrderState().equals("已预订")){
            orderMapper.abnormalOrder(orderid);
            //定了房间到时间却没来，扣信用分。

            int userid = order.getUserId();

            User user = accountService.getUserInfo(userid);
            double beforeCredit = user.getCredit();
            double newCredit = beforeCredit-order.getPrice();
            //更新
            int rowNum2 = accountService.updateAccountCredit(userid,newCredit);

           // LocalDateTime nowTime = LocalDateTime.now();
            String nowDate = nowTime.toLocalDate().toString();
            CreditInfo creditInfo = new CreditInfo();
            //TODO  action感觉应该是string类型
            creditInfo.setAction(CreditAction.OrderErr);
            creditInfo.setTime(nowDate);//设为当前时间
            creditInfo.setOrderId(orderid);
            creditInfo.setChangeVal(-order.getPrice());
            creditInfo.setAfterChange(newCredit);
            creditInfo.setUserId(userid);
            creditMapper.addCreditInfo(creditInfo);
        }
    }

    /**
     * 更新所有订单的异常情况，既每个订单都查一次
     */
    @Override
    public void checkAndUpdateState() {
        List<Order> orders = getAllOrders();
        for (Order order :
                orders) {
            int id = order.getId();
            checkAndUpdateStateOneOrder(id);//调用上一方法
        }
    }


    //执行退房操作
    @Override
    public ResponseVO checkOutOrder(int orderid) {

        Order order = orderMapper.getOrderById(orderid);

        if(!order.getOrderState().equals("已执行")){
            return ResponseVO.buildSuccess(false);
        }
        //更新状态为已退房
        int rowNum = orderMapper.checkOutOrder(orderid);

        //更新退房日期
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime nowTime = LocalDateTime.now();
        String nowDate = nowTime.toLocalDate().toString();
        orderMapper.updateOrderCheckOutDate(orderid,nowDate);
        //更新库存表
        //修改roomrepo表
        //获取roomId
        HotelRoom hotelRoom = roomService.selectRoomByHotelIdAndType(order.getHotelId(),order.getRoomType());
        int roomId = hotelRoom.getId();
//            roomRepoService里面写set(roomid ,start,end,newValue)和get(roomid ,start,end) TODO
        String checkInDate = order.getCheckInDate();
        String checkOutDate = order.getCheckOutDate();
        roomRepoService.updateAvailableOfRoomIdAndDates(roomId,checkInDate,checkOutDate,order.getRoomNum());
        //返回
        if (rowNum>0){return ResponseVO.buildSuccess(true);}
        else return ResponseVO.buildSuccess(false);

    }


    //TODO 更新库存信息
    //一个订单是否需要自动强制退房（房间到期自动退房）
    //TODO 扣信用分?不确定，订单异常才扣
    @Override
    public void checkIfForceCheckOutOne(int orderid) {
        Order order = orderMapper.getOrderById(orderid);

        //更新退房日期
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime nowTime = LocalDateTime.now();
       // nowTime=nowTime.plusDays(1);

        String scheduledCheckOutDate = order.getCheckOutDate();
        //当天 之后可能会有改变的 因为退房日期可能变 TODO
        LocalDateTime scheduledCheckOutDate2 = LocalDateTime.parse(scheduledCheckOutDate+" 00:00:00", formatter);
        //下面一天
        scheduledCheckOutDate2 = scheduledCheckOutDate2.plusDays(1);
        //可能有异常订单? TODO
        if(nowTime.isAfter(scheduledCheckOutDate2) && order.getOrderState().equals("已执行")){
            //退房 更新状态
            int rowNum = orderMapper.checkOutOrder(orderid);
            //更新日期
            String nowDate = nowTime.toLocalDate().toString();
            orderMapper.updateOrderCheckOutDate(orderid,nowDate);

            //更新库存表
            //修改roomrepo表
            //获取roomId
            HotelRoom hotelRoom = roomService.selectRoomByHotelIdAndType(order.getHotelId(),order.getRoomType());
            int roomId = hotelRoom.getId();
            String checkInDate = order.getCheckInDate();
            String checkOutDate = order.getCheckOutDate();
            roomRepoService.updateAvailableOfRoomIdAndDates(roomId,checkOutDate,checkOutDate,order.getRoomNum());
        }



    }


    //检查所有订单需要自动强制退房的情况
    @Override
    public void checkIfForceCheckOut() {
        List<Order> orders = getAllOrders();
        for (Order order :
                orders) {
            int id = order.getId();
            checkIfForceCheckOutOne(id);
        }
    }


    //zl
    //浏览每日未执行订单情况,只在当天的
    @Override
    public ResponseVO abnormalOrdersOfTheDay(int hotelId) {
        List<Order> abnormalOrders = orderMapper.getabnormalOrdersOfTheDay(hotelId);
        if(abnormalOrders.size()==0){
            return ResponseVO.buildSuccess("今天没有未执行的异常订单");
        }
        else return ResponseVO.buildSuccess(abnormalOrders);

    }


    //
    @Override
    public List<Order> managedOrders(int managerId) {
        // 获取所有
        List<HotelVO> hotels = hotelService.selectManagedBy(managerId);
        List<Order> orders = new ArrayList<Order>();
        for (HotelVO hotel : hotels
        ) {
            List<Order> thisOrders = getOrdersByHotelId(hotel.getId());
            orders.addAll(thisOrders);
        }
        return orders;
    }

    //zl
    //C.ii.2
    //线下申诉异常订单
    @Override
    public ResponseVO appealAbnormalOrder(int orderId) {
        Order order = orderMapper.getOrderById(orderId);
        if(order.getOrderState().equals("异常")) {
            int rowNum = orderMapper.appealAbnormalOrder(orderId);
            if (rowNum > 0) {

                double price = order.getPrice();
                //加回来credit,加回全部
                Integer userid = order.getUserId();
                User user = accountService.getUserInfo(userid);
                double newCredit = user.getCredit() + price;
                accountService.updateAccountCredit(userid,newCredit);
                //给credit表也插入记录
                CreditInfo creditInfo = new CreditInfo();
                //TODO  action感觉应该是string类型
                LocalDateTime nowTime = LocalDateTime.now();
                String nowDate = nowTime.toLocalDate().toString();
                creditInfo.setAction(CreditAction.OrderRetreat);
                creditInfo.setTime(nowDate);//设为当前时间
                creditInfo.setOrderId(orderId);
                creditInfo.setChangeVal(order.getPrice());
                creditInfo.setAfterChange(newCredit);
                creditInfo.setUserId(userid);
                creditMapper.addCreditInfo(creditInfo);
                HotelRoom hotelRoom = roomService.selectRoomByHotelIdAndType(order.getHotelId(),order.getRoomType());
                int roomId = hotelRoom.getId();
//            roomRepoService里面写set(roomid ,start,end,newValue)和get(roomid ,start,end) TODO
                String checkInDate = order.getCheckInDate();
                String checkOutDate = order.getCheckOutDate();
                //可能有问题
                roomRepoService.updateAvailableOfRoomIdAndDates(roomId,checkInDate,checkOutDate,order.getRoomNum());
                //返回
                return ResponseVO.buildSuccess(true);

            }
            else return ResponseVO.buildFailure("申诉失败");
        }else return ResponseVO.buildFailure("申诉失败");
    }


    //删除订单
    @Override
    public ResponseVO deleteOrder(int orderId) {
        if(orderMapper.deleteOrder(orderId)>0)return ResponseVO.buildSuccess(true);
        return ResponseVO.buildFailure("删除失败");
    }


    //获取订过的酒店
    @Override
    public List<Integer> getOrderedHotels(int userId) {
        return orderMapper.getOrderedHotels(userId);
    }



    @Override
    public Integer getOrderedNumOfThisRoomType(RoomType roomType, String date, Integer hotelId) {
        Integer res=0;
        List<Order> orders = orderMapper.getOrderedNumOfThisRoomType(roomType, hotelId);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime date2 = LocalDateTime.parse(date+" 00:00:00", formatter);
        date2 = date2.plusHours(12);
        for (Order order :
                orders) {
            String checkIndateStr = order.getCheckInDate();
            String checkOutdateStr=  order.getCheckOutDate();
            LocalDateTime checkInDate = LocalDateTime.parse(checkIndateStr+" 00:00:00", formatter);
            LocalDateTime checkOutDate = LocalDateTime.parse(checkOutdateStr+" 00:00:00", formatter);
            checkOutDate = checkOutDate.plusHours(24);
            if(checkInDate.isBefore(date2)
                    && checkOutDate.isAfter(date2)
                    && (order.getOrderState().equals("已预订")
                            ||order.getOrderState().equals("已执行")
                            ||order.getOrderState().equals("异常"))){
                res+=order.getRoomNum();
            }

        }

        return res;


    }

    public Object getMinValue(Map<String, Integer> map) {
        if (map == null)
            return null;
        Collection<Integer> c = map.values();
        Object[] obj = c.toArray();
        Arrays.sort(obj);
        return obj[0];
    }


    //根据酒店ID查其下所有订单信息
    @Override
    public List<Order> getOrdersByHotelId(Integer hotelId) {
        return orderMapper.getOrdersByHotelId(hotelId);
    }


    //更新订单的总方法
    @Override
    public void update(Observable o, Object arg) {
        checkAndUpdateState();
        checkIfForceCheckOut();
    }
}
